/**
 * 
 */
package jocl.samples;

import static org.jocl.CL.CL_DEVICE_TYPE_ALL;
import static org.jocl.CL.clGetDeviceIDs;
import static org.jocl.CL.clGetPlatformIDs;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.jocl.CL;
import org.jocl.cl_platform_id;

import sw.utils.JOCLUtils;

/**
 * @author Chung
 *
 */
public class MultiPlatformComputing {
	
	 private String programSource =
	            "__kernel void sampleKernel(__global const float *input,"+
	                    "                           __global float *output, " +
	                    "                           int size)"+
	                    "{"+
	                    "    int gid = get_global_id(0);"+
	                    "    output[gid] = 0;" +
	                    "    for (int i=0; i<size; i++) " +
	                    "        output[gid] += input[i];" +
	                    "}";

//	 final long deviceType = CL_DEVICE_TYPE_ALL;
	 
	 private void compute(int n) {
		// Enable exceptions and subsequently omit error checks in this sample
		CL.setExceptionsEnabled(true);

		// Obtain the number of platforms
		int numPlatformsArray[] = new int[1];
		clGetPlatformIDs(0, null, numPlatformsArray);
		int numPlatforms = numPlatformsArray[0];
		
		 // Obtain a platform ID
        cl_platform_id platforms[] = new cl_platform_id[numPlatforms];
        clGetPlatformIDs(platforms.length, platforms, null);
        
        int numberDevices = 0;
        long deviceType = 0;
        // calculate total number of devices in computer
        for (cl_platform_id platform : platforms) {
        	// get number of devices
    		int numDevicesArray[] = new int[1];
    		
    		String platformName = JOCLUtils.getString(platform, CL.CL_PLATFORM_NAME);
        	if (platformName.contains("Intel")) {
        		deviceType = CL.CL_DEVICE_TYPE_CPU;
        	} else {
        		deviceType = CL.CL_DEVICE_TYPE_GPU;
        	}
    		
    	    clGetDeviceIDs(platform, deviceType, 0, null, numDevicesArray);	   
    		numberDevices += numDevicesArray[0];
        }
        
        // remaning
        int mod = n % numberDevices;
        int globalSize = n / numberDevices;
        System.out.println(globalSize);
//        int size[] = new int[numberDevices];
        
        // init size array
//        Arrays.fill(size, calEachDevice);
//        size[0] = size[0] + mod;
        
        // Execute the kernel on each command queue, and
        // create events for each kernel launch
        ExecutorService executor = Executors.newFixedThreadPool(10);
        List<Runnable> list = new ArrayList<Runnable>(0);               
                
       
        for (int i = 0 ; i < platforms.length; i++) {
        	cl_platform_id platform = platforms[i];
        	String platformName = JOCLUtils.getString(platform, CL.CL_PLATFORM_NAME);
        	if (platformName.contains("Intel")) {
        		deviceType = CL.CL_DEVICE_TYPE_CPU;
        	} else {
        		deviceType = CL.CL_DEVICE_TYPE_GPU;
        	}
        	Runnable worker = new PlatformComputation(platform, n, programSource, globalSize, deviceType);        	
        	list.add(worker);
        }
        
        long before = System.nanoTime();
		for (Runnable worker : list) {
			executor.execute(worker);
		}
		// no new thread accepted
		executor.shutdown();
		try {
			// will wait till all threads finished, otherwise, will wait till
			// timeout
			executor.awaitTermination(60, TimeUnit.SECONDS);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		long after = System.nanoTime();
		float totalDurationMs = (after - before) / 1e6f;
		System.out.println("Total duration: " + totalDurationMs + "ms");
	 }
	 
	 
	 public static void main(String args[]) {
		 try {
			 int n = 180000;
			 new MultiPlatformComputing().compute(n);
		 } catch (Exception e) {
			 e.printStackTrace();
		 }
	 }
}
